name: Compilations

on:
  push:
    paths-ignore:
      - 'doc/**'
      - '**/man'
      - '**.md'
      - '**.rdoc'
      - '**/.document'
  pull_request:
    paths-ignore:
      - 'doc/**'
      - '**/man'
      - '**.md'
      - '**.rdoc'
      - '**/.document'
  merge_group:
    paths-ignore:
      - 'doc/**'
      - '**/man'
      - '**.md'
      - '**.rdoc'
      - '**/.document'

concurrency:
  group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
  cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}

# GitHub actions does not support YAML anchors.  This creative use of
# environment variables (plus the "echo $GITHUB_ENV" hack) is to reroute that
# restriction.
env:
  default_cc: clang-16
  append_cc: ''

  # -O1 is faster than -O3 in our tests... Majority of time are consumed trying
  # to optimize binaries.  Also GitHub Actions run on relatively modern CPUs
  # compared to, say, GCC 4 or Clang 3.  We don't specify `-march=native`
  # because compilers tend not understand what the CPU is.
  optflags: '-O1'

  # -g0 disables backtraces when SEGV.  Do not set that.
  debugflags: '-ggdb3'

  default_configure: >-
    --enable-debug-env
    --disable-install-doc
    --with-ext=-test-/cxxanyargs,+
  append_configure: >-
    --without-valgrind
    --without-jemalloc
    --without-gmp

  CONFIGURE_TTY: never
  GITPULLOPTIONS: --no-tags origin ${{github.ref}}
  RUBY_DEBUG: ci rgengc
  RUBY_TESTOPTS: >-
    -q
    --color=always
    --tty=no

permissions:
  contents: read

jobs:
  compile:
    strategy:
      fail-fast: false
      matrix:
        env:
          - {}
        entry:
          - { name: gcc-13,    env: { default_cc: gcc-13 } }
          - { name: gcc-12,    env: { default_cc: gcc-12 } }
          - { name: gcc-11,    env: { default_cc: gcc-11 } }
          - { name: gcc-10,    env: { default_cc: gcc-10 } }
          - { name: gcc-9,     env: { default_cc: gcc-9 } }
          - { name: gcc-8,     env: { default_cc: gcc-8 } }
          - { name: gcc-7,     env: { default_cc: gcc-7 } }
          - name: 'gcc-13 LTO'
            container: gcc-13
            env:
              default_cc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
              optflags: '-O2'
            shared: disable
            # check: true
          - { name: clang-17,  env: { default_cc: clang-17 } }
          - { name: clang-16,  env: { default_cc: clang-16 } }
          - { name: clang-15,  env: { default_cc: clang-15 } }
          - { name: clang-14,  env: { default_cc: clang-14 } }
          - { name: clang-13,  env: { default_cc: clang-13 } }
          - { name: clang-12,  env: { default_cc: clang-12 } }
          - { name: clang-11,  env: { default_cc: clang-11 } }
          - { name: clang-10,  env: { default_cc: clang-10 } }
          - { name: clang-9,   env: { default_cc: clang-9 } }
          - { name: clang-8,   env: { default_cc: clang-8 } }
          - { name: clang-7,   env: { default_cc: clang-7 } }
          - { name: clang-6.0, env: { default_cc: clang-6.0 } }
          - name: 'clang-16 LTO'
            container: clang-16
            env:
              default_cc: 'clang-16 -flto=auto'
              optflags: '-O2'
            shared: disable
            # check: true

          - { name: ext/Setup }

#         - { name: aarch64-linux-gnu,     crosshost: aarch64-linux-gnu, container: crossbuild-essential-arm64 }
#         - { name: arm-linux-gnueabi,     crosshost: arm-linux-gnueabi }
#         - { name: arm-linux-gnueabihf,   crosshost: arm-linux-gnueabihf }
#         - { name: i686-w64-mingw32,      crosshost: i686-w64-mingw32 }
#         - { name: powerpc-linux-gnu,     crosshost: powerpc-linux-gnu }
#         - { name: powerpc64le-linux-gnu, crosshost: powerpc64le-linux-gnu, container: crossbuild-essential-ppc64el }
#         - { name: s390x-linux-gnu,       crosshost: s390x-linux-gnu, container: crossbuild-essential-s390x }
#         - { name: x86_64-w64-mingw32,    crosshost: x86_64-w64-mingw32, container: mingw-w64 }

          # -Wno-strict-prototypes is necessary with current clang-15 since
          # older autoconf generate functions without prototype and -pedantic
          # now implies strict-prototypes. Disabling the error but leaving the
          # warning generates a lot of noise from use of ANYARGS in
          # rb_define_method() and friends.
          # See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94
          - { name: c99,   env: { append_cc: '-std=c99   -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
#         - { name: c11,   env: { append_cc: '-std=c11   -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
#         - { name: c17,   env: { append_cc: '-std=c17   -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
          - { name: c2x,   env: { append_cc: '-std=c2x   -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
          - { name: c++98, env: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
#         - { name: c++11, env: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
#         - { name: c++14, env: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
#         - { name: c++17, env: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
          - { name: c++2a, env: { CXXFLAGS: '-std=c++2a -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }

          - { name: '-O0', env: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
#         - { name: '-O3', env: { optflags: '-O3 -march=x86-64 -mtune=generic' }, check: true }

          - { name: gmp,                  env: { append_configure: '--with-gmp' } }
          - { name: jemalloc,             env: { append_configure: '--with-jemalloc' } }
          - { name: valgrind,             env: { append_configure: '--with-valgrind' } }
          - { name: 'coroutine=ucontext', env: { append_configure: '--with-coroutine=ucontext' } }
          - { name: 'coroutine=pthread',  env: { append_configure: '--with-coroutine=pthread' } }
          - { name: disable-jit-support,  env: { append_configure: '--disable-jit-support' } }
          - { name: disable-dln,          env: { append_configure: '--disable-dln' } }
          - { name: enable-mkmf-verbose,  env: { append_configure: '--enable-mkmf-verbose' } }
          - { name: disable-rubygems,     env: { append_configure: '--disable-rubygems' } }
          - { name: RUBY_DEVEL,           env: { append_configure: '--enable-devel' } }

          - { name: OPT_THREADED_CODE=1,            env: { cppflags: '-DOPT_THREADED_CODE=1' } }
          - { name: OPT_THREADED_CODE=2,            env: { cppflags: '-DOPT_THREADED_CODE=2' } }
          - { name: OPT_THREADED_CODE=3,            env: { cppflags: '-DOPT_THREADED_CODE=3' } }

          - { name: NDEBUG,                         env: { cppflags: '-DNDEBUG' } }
          - { name: RUBY_DEBUG,                     env: { cppflags: '-DRUBY_DEBUG' } }
#         - { name: ARRAY_DEBUG,                    env: { cppflags: '-DARRAY_DEBUG' } }
#         - { name: BIGNUM_DEBUG,                   env: { cppflags: '-DBIGNUM_DEBUG' } }
#         - { name: CCAN_LIST_DEBUG,                env: { cppflags: '-DCCAN_LIST_DEBUG' } }
#         - { name: CPDEBUG=-1,                     env: { cppflags: '-DCPDEBUG=-1' } }
#         - { name: ENC_DEBUG,                      env: { cppflags: '-DENC_DEBUG' } }
#         - { name: GC_DEBUG,                       env: { cppflags: '-DGC_DEBUG' } }
#         - { name: HASH_DEBUG,                     env: { cppflags: '-DHASH_DEBUG' } }
#         - { name: ID_TABLE_DEBUG,                 env: { cppflags: '-DID_TABLE_DEBUG' } }
#         - { name: RGENGC_DEBUG=-1,                env: { cppflags: '-DRGENGC_DEBUG=-1' } }
#         - { name: SYMBOL_DEBUG,                   env: { cppflags: '-DSYMBOL_DEBUG' } }

#         - { name: RGENGC_CHECK_MODE,              env: { cppflags: '-DRGENGC_CHECK_MODE' } }
#         - { name: TRANSIENT_HEAP_CHECK_MODE,      env: { cppflags: '-DTRANSIENT_HEAP_CHECK_MODE' } }
#         - { name: VM_CHECK_MODE,                  env: { cppflags: '-DVM_CHECK_MODE' } }

          - { name: USE_EMBED_CI=0,                 env: { cppflags: '-DUSE_EMBED_CI=0' } }
          - { name: USE_FLONUM=0,                   env: { cppflags: '-DUSE_FLONUM=0' } }
#         - { name: USE_GC_MALLOC_OBJ_INFO_DETAILS, env: { cppflags: '-DUSE_GC_MALLOC_OBJ_INFO_DETAILS' } }
          - { name: USE_LAZY_LOAD,                  env: { cppflags: '-DUSE_LAZY_LOAD' } }
#         - { name: USE_SYMBOL_GC=0,                env: { cppflags: '-DUSE_SYMBOL_GC=0' } }
#         - { name: USE_THREAD_CACHE=0,             env: { cppflags: '-DUSE_THREAD_CACHE=0' } }
#         - { name: USE_TRANSIENT_HEAP=0,           env: { cppflags: '-DUSE_TRANSIENT_HEAP=0' } }
          - { name: USE_RUBY_DEBUG_LOG=1,           env: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
#         - { name: USE_DEBUG_COUNTER,              env: { cppflags: '-DUSE_DEBUG_COUNTER=1', RUBY_DEBUG_COUNTER_DISABLE: '1' } }

          - { name: DEBUG_FIND_TIME_NUMGUESS,       env: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
          - { name: DEBUG_INTEGER_PACK,             env: { cppflags: '-DDEBUG_INTEGER_PACK' } }
#         - { name: ENABLE_PATH_CHECK,              env: { cppflags: '-DENABLE_PATH_CHECK' } }

          - { name: GC_DEBUG_STRESS_TO_CLASS,       env: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
#         - { name: GC_ENABLE_LAZY_SWEEP=0,         env: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' } }
#         - { name: GC_PROFILE_DETAIL_MEMOTY,       env: { cppflags: '-DGC_PROFILE_DETAIL_MEMOTY' } }
#         - { name: GC_PROFILE_MORE_DETAIL,         env: { cppflags: '-DGC_PROFILE_MORE_DETAIL' } }

#         - { name: CALC_EXACT_MALLOC_SIZE,         env: { cppflags: '-DCALC_EXACT_MALLOC_SIZE' } }
#         - { name: MALLOC_ALLOCATED_SIZE_CHECK,    env: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' } }

#         - { name: IBF_ISEQ_ENABLE_LOCAL_BUFFER,   env: { cppflags: '-DIBF_ISEQ_ENABLE_LOCAL_BUFFER' } }

#         - { name: RGENGC_ESTIMATE_OLDMALLOC,      env: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' } }
#         - { name: RGENGC_FORCE_MAJOR_GC,          env: { cppflags: '-DRGENGC_FORCE_MAJOR_GC' } }
#         - { name: RGENGC_OBJ_INFO,                env: { cppflags: '-DRGENGC_OBJ_INFO' } }
#         - { name: RGENGC_OLD_NEWOBJ_CHECK,        env: { cppflags: '-DRGENGC_OLD_NEWOBJ_CHECK' } }
#         - { name: RGENGC_PROFILE,                 env: { cppflags: '-DRGENGC_PROFILE' } }

#         - { name: VM_DEBUG_BP_CHECK,              env: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
#         - { name: VM_DEBUG_VERIFY_METHOD_CACHE,   env: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }

          - { name: enable-yjit,                    env: { append_configure: '--enable-yjit --disable-rjit' }, rust: true }
          - { name: enable-rjit,                    env: { append_configure: '--enable-rjit --disable-yjit' } }
          - { name: YJIT_FORCE_ENABLE,              env: { cppflags: '-DYJIT_FORCE_ENABLE' }, rust: true }
#         - { name: RJIT_FORCE_ENABLE,              env: { cppflags: '-DRJIT_FORCE_ENABLE' } }

    name: ${{ matrix.entry.name }}
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || matrix.entry.env.default_cc || 'clang-16' }}
      options: --user root
    if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
    env: ${{ matrix.entry.env || matrix.env }}
    steps:
      - run: id
        working-directory:
      - run: mkdir build
        working-directory:
      - name: setenv
        run: |
          echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> $GITHUB_ENV
      - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
        with:
          path: src
      - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        with:
          path: src/.downloaded-cache
          key: downloaded-cache
      - name: Install Rust
        if: ${{ matrix.entry.rust }}
        run: sudo apt-get update && sudo apt install -y rustc
      - name: autogen
        run: |
          if [ ! -f ./autogen.sh ]; then
            ls -la
          fi
          ./autogen.sh
        working-directory: src
      - name: Run configure
        run: >
          ../src/configure -C ${default_configure} ${append_configure}
          --${{
            matrix.entry.crosshost && 'host' || 'with-gcc'
          }}=${{
            matrix.entry.crosshost || '"${default_cc}${append_cc:+ $append_cc}"'
          }}
          --${{ matrix.entry.shared || 'enable' }}-shared
      - name: Add to ext/Setup # statically link just the etc extension
        run: mkdir ext && echo etc >> ext/Setup
        if: ${{ matrix.entry.name == 'ext/Setup' }}
      - run: make extract-extlibs
      - run: make incs
      - run: make showflags
      - run: make
      - run: make test
      - run: make install
        if: ${{ matrix.entry.check }}
      - run: make test-tool
        if: ${{ matrix.entry.check }}
      - run: make test-all TESTS='-- ruby -ext-'
        if: ${{ matrix.entry.check }}
      - run: make test-spec
        env:
          CHECK_LEAKS: true
        if: ${{ matrix.entry.check }}
      - run: make test-annocheck
        if: ${{ matrix.entry.check && endsWith(matrix.entry.name, 'annocheck') }}

      - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
        with:
          payload: |
            {
              "ci": "GitHub Actions",
              "env": "${{ github.workflow }} / ${{ matrix.entry.name }}",
              "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
              "commit": "${{ github.sha }}",
              "branch": "${{ github.ref_name }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
        if: ${{ failure() && github.event_name == 'push' }}

defaults:
  run:
    working-directory: build
